package vpfarm.slave;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;

import jtools.ai.agenten.AMessage;
import jtools.ai.agenten.Agent;
import jtools.ai.agenten.CycleBehavior;
import jtools.files.TextFile;
import jtools.files.filesystem.FileOperation;
import jtools.network.mqueue.Adress;
import jtools.network.mqueue.MessageException;
import vpfarm.Constants;
import vpfarm.data.JobInfo;
import vpfarm.data.RenderResult;
import vpfarm.data.RenderTask;

public class Slave extends Agent {

	public static void main(String[] arg){
		try {
			Slave slave = new Slave(new Adress("localhost", 2001));
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (MessageException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	
	private JobInfo jobInfo;
	private File jobResultDirectory = null;
	
	private File resultDirectory = new File("slaveJob");
	private File jobFrameDirectory = null;
	private String blenderBinary;
	
	
	
	public Slave(Adress adr) throws IOException, MessageException {
		this(adr, false);
	}

	public Slave(Adress adr, boolean b) throws IOException, MessageException {
		super(Constants.SLAVE_NAME, adr, b);
	}

	public void onStart(){
		try {
			resultDirectory = new File(getAID().getGlobalName()+"Jobs");
			addBehavior(new PingBehavior());
			addBehavior(new KillBehavior());
			readBlenderConfig();
			addBehavior(new WaitForJobInfoBehavior(this));
			
			addBehavior(new ReciveRenderTaskBehavior(this));
			
			AMessage register = new AMessage(Constants.REGISTER_SLAVE);
			register.addReciver(Constants.MASTER_NAME);
			sendMessage(register);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private void readBlenderConfig() throws IOException {
		TextFile tf = new TextFile();
		tf.readFile("config/Blender.info", false);
		String w = tf.getNextLine();
		String l = tf.getNextLine();
		tf.closeFile();
		String osName = System.getProperty("os.name").toLowerCase();
		if (osName.contains("win"))
			this.blenderBinary = w;
		else if (osName.contains("lin"))
			this.blenderBinary = l;
	}

	private void initialize() throws IOException {
		this.jobResultDirectory = new File(this.resultDirectory.getAbsolutePath()+File.separator+jobInfo.getJobName()+"_"+jobInfo.getJobID());
		this.jobFrameDirectory = new File(this.jobResultDirectory+File.separator+"frames"+File.separator);
		FileOperation.createDir(jobResultDirectory, true);
		FileOperation.createDir(jobFrameDirectory, true);	
		
		String blenderFilePath = this.jobResultDirectory.getAbsolutePath()+File.separator+"job.blend";
		this.jobInfo.saveFileTo(blenderFilePath);
		
		
		AMessage req = new AMessage(Constants.ASK_FOR_RENDER_TASK);
		req.addReciver(Constants.MASTER_NAME);
		sendMessage(req);
	}

	public void setJobInfo(JobInfo ji) throws IOException {
		this.jobInfo = ji;
		this.initialize();
		
	}

	public void render(RenderTask rt) throws IOException {
		File outputFile = File.createTempFile("vpfarm", ".txt");
		String blenderExe = this.blenderBinary;
		File blenderFile = new File(this.jobInfo.getBlenderFile());
		File targetDir = this.jobFrameDirectory;
		String format = this.jobInfo.formatToString();
		String pref = "_";
		int start = rt.getStart();
		int end = rt.getEnd();
		Blender.render(blenderExe, blenderFile, targetDir, format, pref, start, end, outputFile);
		ArrayList<File> resultList = Blender.parseOutputFile(outputFile);
		FileOperation.delete(outputFile, false);
		ArrayList<RenderResult> rrList = new ArrayList<RenderResult>();
		for (int i = 0; i < resultList.size(); i++){
			File f = resultList.get(i);
			String fn = f.getName();
			String numString = fn.substring(fn.length()-8, fn.length()-4);
			int num = Integer.parseInt(numString);
			rrList.add(new RenderResult(rt.getJobID(), f.getAbsolutePath(), num));
		}
		AMessage msg = new AMessage(Constants.SEND_RENDER_RESULT);
		msg.addReciver(Constants.MASTER_NAME);
		msg.setContent(rrList);
		sendMessage(msg);
		
		AMessage req = new AMessage(Constants.ASK_FOR_RENDER_TASK);
		req.addReciver(Constants.MASTER_NAME);
		sendMessage(req);
	}

	class PingBehavior extends CycleBehavior{

		@Override
		public void execute() {
			AMessage msg = reciveMessage(true);
			if (msg.getSubject() == Constants.PING){
				AMessage rep = msg.createReplay(Constants.PING);
				sendMessage(rep);
			}else
				pushBack(msg);
		}

		@Override
		public void onEnd() {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void onStart() {
			// TODO Auto-generated method stub
			
		}
	}
	class KillBehavior extends CycleBehavior{

		@Override
		public void execute() {
			AMessage msg = reciveMessage(true);
			if (msg.getSubject() == Constants.CLOSE_AGENT){
				myAgent.kill();
			}else
				pushBack(msg);
		}

		@Override
		public void onEnd() {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void onStart() {
			// TODO Auto-generated method stub
			
		}
		
	}
}
